#include "payload.h"
#include <QStringList>
#include <QList>
#include <google/protobuf/descriptor.h>

namespace apollo
{
	namespace core
	{
		QString Payload::DTO_TYPE = QString(QLatin1String("dtotype"));
		QString Payload::SESSION_ID = QString(QLatin1String("sessionid"));

		Payload::Payload(void):bodySize(0), body(NULL)
		{
		}

		Payload::~Payload(void)
		{
			if(body != NULL)
			{
				delete body;
			}
		}
		const QString Payload::getHeader(const QString &key) const
		{

			return header.value(key, QString());
		}

		QString Payload::getHeader() const
		{
			if(header.size() == 0)
			{
				return QString();
			}
			QString sb("");

			for(QHash<QString,QString>::const_iterator it = header.constBegin(); it != header.constEnd(); ++it)
			{
				if(it.key().isNull() || it.key().isEmpty())
				{
					continue;
				}
				if(it.value().isNull() == false && it.value().isEmpty() == false)
				{					
					sb += it.key() + KEY_VALUE_SPLITTER + it.value() + HEADER_SPLITTER;
				}

			}
			if(sb.isNull()  == false && sb.isEmpty() == false)
			{
				sb.truncate(sb.size() - 1);
			}
			return sb;
		}

		void Payload::setHeader(const QString &headerStr)
		{
			if(headerStr.isNull() || headerStr.isEmpty())
			{
				header.clear();
				return;
			}
			QStringList strList = headerStr.split(QString(HEADER_SPLITTER));
			for(QList<QString>::const_iterator it = strList.begin(); it != strList.end(); ++it)
			{
				QString s = *it;
				QStringList keyValue = s.split(QString(KEY_VALUE_SPLITTER));
				if(keyValue.size() == 1)
				{
					header.insert(keyValue.at(0), QString() );
				}
				else if(keyValue.size() == 2)
				{				
					header.insert(keyValue.at(0), keyValue.at(1));
				} 
				else
				{
					QString key = keyValue.at(0);
					keyValue.removeAt(0);
					header.insert(key,keyValue.join(QString(KEY_VALUE_SPLITTER)));
				}
			}
		}

		void Payload::addHeader(const QString &key, const QString &value)
		{
			Q_ASSERT_X(key.isNull() == false && key.isEmpty() == false && key.contains('=') == false, "Payload::addHeader", "Key can not be null or empty or contains = char.");
			header.insert(key, value);

		}
		void Payload::removeHeader(const QString &key)
		{
			Q_ASSERT_X(key.isNull() == false && key.isEmpty() == false && key.contains('=') == false, "Payload::addHeader", "Key can not be null or empty or contains = char.");
			header.remove(key);
		}
		void Payload::setBody(const google::protobuf::Message* message)
		{
			if(body != NULL)
			{
				delete body;
			}
			std::string content = message->SerializeAsString();
			
			bodySize = content.size();
			body = new char[bodySize];
			std::copy(content.begin(), content.end(), body);
			addHeader(DTO_TYPE, QString::fromStdString(message->GetTypeName()));
		}

		MessagePtr Payload::getMessage() const
		{
			if(body == NULL || bodySize == 0)
			{
				return MessagePtr(NULL);
			}
			QString dtotype = getHeader(DTO_TYPE);
			Q_ASSERT_X(dtotype.isNull() == false , "Payload::getMessage", "Header does not contain dtotype.");
			google::protobuf::Message* message = NULL;
			const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(dtotype.toStdString());
			if (descriptor)
			{
				const google::protobuf::Message* prototype =	google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
				if (prototype)
				{
					message = prototype->New();
					message->ParseFromArray(body,bodySize);
				}
			}
			return MessagePtr(message);
		}
	}//namespace core
}
